#include "npc_exec.h"
#include "../disasm.cc"
#include <SDL2/SDL.h>
//////////////////////////////////////////
//////////////////////////////////////////
extern uint32_t *pc_gpr;
extern int ebreak;
// extern int pc_reg[0x8000000];
#ifdef ITRACE
  extern void disassemble(char *str, int size, uint64_t pc, uint8_t *code, int nbyte);
#endif
#ifdef DIFFTEST
extern void ref_difftest_test();
extern void difftest_step(word_t pc, word_t npc);
extern void difftest_skip_ref();
extern void difftest_initr(uint64_t NO);
#endif
#ifdef VGA
extern void vga_update_screen();
#endif
#ifdef KEYBOARD
extern void send_key(uint8_t scancode, bool is_keydown);
#endif
//////////////////////////////////////////
//////////////////////////////////////////
#ifdef ITRACE
  	char logbuf [128];//ITRACE打印数组所存的地方
#endif
uint64_t timer = 0;
NPCState npc_state;
CPU_state cpu = {};
Vysyx_22050369_cpu* top;
VerilatedContext* contextp;
#ifdef TRACE
VerilatedVcdC* tfp; //初始化VCD对象指针
#endif
#ifdef FTRACE
typedef struct func {
	uint64_t start;
	uint64_t size;
	uint64_t end;
	struct func *next;
	char  name [100];
} FC;
char * 	pace_deep=NULL;
char * 	pace_temp=NULL;
int 	deep_max = 0;
extern 	FC *fc_head;
int 	func_deep = 0;
char 	now_func [100] ;
char  	peace[100];
#endif
//////////////////////////////////////////
//////// Function get_cpu_reg
//////////////////////////////////////////
void get_cpu_reg(){
    extern uint64_t *cpu_gpr ;
    extern uint32_t *pc_gpr;
    uint64_t op=-1;
    for (int i = 0; i < 32; i++) {
        cpu.gpr[i]= cpu_gpr[i];
    }
     cpu.pc= pc_gpr[1]&op;
#ifdef DISPLAY
	printf("timer = %d\n",timer);
	printf("cpu.pc = 0x%lx\n",cpu.pc);
#endif
}
//////////////////////////////////////////
//////////////////////////////////////////

//////////////////////////////////////////
//////// Function creat_Context
//////////////////////////////////////////
void creat_Context(){
    contextp = new VerilatedContext;
  	// contextp->commandArgs(argc, argv);
  	top = new Vysyx_22050369_cpu{contextp}; 
#ifdef TRACE
  	tfp = new VerilatedVcdC; //初始化VCD对象指针
  	contextp->traceEverOn(true); //打开追踪功能
  	top->trace(tfp, 0); //
  	tfp->open("wave.vcd"); //设置输出的文件wave.vcd
#endif
}
//////////////////////////////////////////
//////////////////////////////////////////

//////////////////////////////////////////
//////// Function write_log
//////// 主要在log文件中写入运行的信息   
//////// disassemble函数是llvm库的反汇编函数
//////////////////////////////////////////
#ifdef ITRACE
    void write_log(){
        char *p =logbuf;
        uint32_t pc_val,inst_val;
        p += snprintf(p, sizeof(logbuf), "0x%016x" ":", pc_gpr[1]);
        int ilen = 4;
        int i;
        uint8_t *inst = (uint8_t *)&pc_gpr[0];
        for (i = ilen - 1; i >= 0; i --) {
            p += snprintf(p, 4, " %02x",inst[i]);
        }
        int ilen_max =  4;
        int space_len = ilen_max - ilen;
        if (space_len < 0) space_len = 0;
        space_len = space_len * 3 + 1;
        memset(p, ' ', space_len);
        p += space_len;
        inst_val = pc_gpr[0];
        pc_val = pc_gpr[1];
        disassemble(p, 96,pc_val, (uint8_t *)&inst_val, 4);  
        extern FILE* log_fp;
        fprintf(log_fp,"%s\n",logbuf);
         fflush(log_fp); 
    }   
#endif 
//////////////////////////////////////////
//////////////////////////////////////////
#ifdef FTRACE

//////////////////////////////////////////
//////// Function write_peace
//////////////////////////////////////////
void write_peace(){
    memset(peace, 0, sizeof(peace));
    strcpy(peace,"  ");
    for (size_t i = 0; i < func_deep; i++)
    {
        strcat(peace,"  ");
    }
}
//////////////////////////////////////////
//////////////////////////////////////////

//////////////////////////////////////////
//////// Function trace_func
//////////////////////////////////////////
void trace_func(uint64_t nxpc,uint64_t pc,uint32_t inst){
  FC*p = fc_head;
  while (p)
  {
    if ( nxpc == p->start)
    {
		
      if (inst == 0x00008067)
      {
        write_peace();
        printf("0x%lx:  %sreturn  [%s]\n",pc,peace,p->name);
        strcpy(now_func,p->name);
        func_deep = func_deep -1;
        break;
      }
      else{
        func_deep = func_deep +1;
        write_peace();
        printf("0x%lx:  %scall  [%s@0x%lx]\n",pc,peace,p->name,p->start);
        strcpy(now_func,p->name);
        break;
      }
    }
    else if (nxpc > p->start && nxpc <= p->end)
    {
      
      if (inst == 0x00008067)
      {
        write_peace();
        printf("0x%lx:  %sreturn  [%s]\n",pc,peace,p->name);
        strcpy(now_func,p->name);
        func_deep = func_deep -1;
        break;
      }
      else if (inst%0x80 == 0x6f || inst%0x80 == 0x67)
      {
        if (strcmp(now_func,p->name))
        {
          func_deep = func_deep +1;
          write_peace();
          printf("0x%lx:  %scall  [%s@0x%lx]\n",pc,peace,p->name,p->start);
          strcpy(now_func,p->name);
        }
        break;
      }
    }
    p=p->next;
  }
}
//////////////////////////////////////////
//////////////////////////////////////////
#endif
//////////////////////////////////////////
//////// Function rst   复位函数
//////////////////////////////////////////
uint32_t device=0;
uint32_t run=0;
uint32_t run_cnt=0;
uint32_t ecall_flag=0;
int counter= 0;
void rst(){
#ifdef ITRACE
	init_disasm("riscv64-pc-linux-gnu"); //在使用llvm库之前初始化
#endif
    while (timer <=10 && !ebreak) {
        if(timer %2 == 0){
            
            top->clk =0;
        }
        else  if(timer %2 == 1){
            top->clk =1;
        }
            
        if(timer<10){
			top->rst=1;
		} 
        else{
            top->rst = 0;
// #ifdef DIFFTEST
// 			get_cpu_reg();//在复位完成的时候存下来寄存器的值为后，方便difftest使用
// #endif
        }
        top->eval();
        timer = timer +1;
#ifdef TRACE
        tfp->dump(contextp->time()); //dump wave
#endif
        contextp->timeInc(1); //推动仿真时间
	}
}
//////////////////////////////////////////
//////////////////////////////////////////

//////////////////////////////////////////
//////// Function rst   执行函数
//////////////////////////////////////////

void exec(uint64_t n){
  
    uint64_t cnt=0;
	while (cnt <n && npc_state.state==NPC_RUNNING) {
        if(timer %2 == 0){
            top->clk =0;
            cnt ++;
        }
        else  if(timer %2 == 1){
            top->clk =1;
        }
        top->eval();
        timer = timer +1;

#ifdef TRACE
// if (timer >68000000)

        tfp->dump(contextp->time()); //dump wave

#endif
        contextp->timeInc(1); //推动仿真时间
        if(timer %2 == 0){
#ifdef ITRACE
            write_log();
#endif
#ifdef FTRACE
            trace_func(pc_gpr[2],pc_gpr[1],pc_gpr[0]);
#endif

#ifdef VGA
	SDL_Event event;
	while (SDL_PollEvent(&event)) {
		switch (event.type) {
		case SDL_QUIT:
        npc_state.state = NPC_QUIT;
        break;
	#ifdef KEYBOARD
		case SDL_KEYDOWN:
		case SDL_KEYUP: {
			uint8_t k = event.key.keysym.scancode;
			bool is_keydown = (event.key.type == SDL_KEYDOWN);
			send_key(k, is_keydown);
			break;
		}
	#endif
		default: break;
		}
	}
#endif

#ifdef DIFFTEST
	run = pc_gpr[4];
	if (run&0x1 != 0)
	{
    run_cnt ++;
		get_cpu_reg();
    
    if ((device&0x1)!=0)
    {
      difftest_skip_ref();
    }
    if( pc_gpr[1]>=0x8000000){
      difftest_step(pc_gpr[1],pc_gpr[2]);
    }
    device = pc_gpr[3];
	}
#endif		
        }     
	}
}
//////////////////////////////////////////
//////////////////////////////////////////
//////////////////////////////////////////
//////// Function  delete_Context   
//////////////////////////////////////////
void delete_Context(){
    top->final();
#ifdef TRACE
  	tfp->close();; //初始化VCD对象指针
#endif
  delete top;
  	delete contextp;
	
}
//////////////////////////////////////////
//////////////////////////////////////////
 uint32_t *Vstop_cnt = 0;
int check_state(){
  printf("timer       = %ld \n",timer);
  if (npc_state.state==NPC_END || npc_state.state==NPC_QUIT)
  {
    return 0;
  }
  else{
    return -1;
  }
}